import { cloneDeep } from "lodash-es";
import type { AppRouteModule, AppRouteRecordRaw, Menu, MenuModule } from "@/routers/types";
import { findPath, treeMap } from "@/utils/helper/treeHelper";
import { isHttpUrl } from "@/utils/is";
import type { MenuProps } from "antd";
import React from "react";
import { Icon } from "@/components/Icon";

type RouteParams = Record<string, string | string[]>;

export function getAllParentPath<T = Recordable>(treeData: T[], path: string) {
	const menuList = findPath(treeData, n => n.path === path) as Menu[];
	return (menuList || []).map(item => item.path);
}

/**start:route process old  */

type MenuItem = Required<MenuProps>["items"][number];

const getItem = (
	label: React.ReactNode,
	key?: React.Key | null,
	icon?: React.ReactNode,
	children?: MenuItem[],
	type?: "group"
): MenuItem => {
	return {
		key,
		icon,
		children,
		label,
		type
	} as MenuItem;
};

const addIcon = (icon: string) => {
	return React.createElement(Icon, {
		icon
	});
};

// 路径处理
export const joinParentPath = (menus: Menu.MenuOptions[], parentPath = "") => {
	for (let index = 0; index < menus.length; index++) {
		const menu = menus[index];
		// Note that nested paths that start with / will be treated as a root path.
		// This allows you to leverage the component nesting without having to use a nested URL.
		if (menu.path && !(menu.path.startsWith("/") || isHttpUrl(menu.path))) {
			// path doesn't start with /, nor is it a url, join parent path
			menu.path = `${parentPath}/${menu.path}`;
		}
		if (menu?.children?.length) joinParentPath(menu.children, menu?.meta?.hidePathForChildren ? parentPath : menu.path);
	}
};

export const deepLoopFloat = (menuList: Menu.MenuOptions[], newArr: MenuItem[] = []): MenuItem[] => {
	menuList.forEach((item: Menu.MenuOptions) => {
		if (!item?.children?.length) return newArr.push(getItem(item.name, item.path, addIcon(item.icon!)));
		newArr.push(getItem(item.name, item.path, addIcon(item.icon!), deepLoopFloat(item.children)));
	});
	return newArr;
};

/**end:route process old  */

// Parsing the menu module
export function transformMenuModule(menuModule: MenuModule): Menu {
	const { menu } = menuModule;

	const menuList = [menu];

	joinParentPath(menuList);
	return menuList[0];
}

// 将路由转换成菜单
export function transformRouteToMenu(routeModList: AppRouteModule[], routerMapping = false) {
	// 借助 lodash 深拷贝
	const cloneRouteModList = cloneDeep(routeModList);
	const routeList: AppRouteRecordRaw[] = [];

	// 对路由项进行修改
	cloneRouteModList.forEach(item => {
		if (routerMapping && item.meta.hideChildrenInMenu && typeof item.redirect === "string") item.path = item.redirect;

		if (item.meta?.single) {
			const realItem = item?.children?.[0];
			realItem && routeList.push(realItem);
		} else {
			routeList.push(item);
		}
	});
	// 提取树指定结构
	const list = treeMap(routeList, {
		conversion: (node: AppRouteRecordRaw) => {
			const { meta: { title, hideMenu = false } = {} } = node;

			return {
				...(node.meta || {}),
				meta: node.meta,
				name: title,
				hideMenu,
				path: node.path,
				...(node.redirect ? { redirect: node.redirect } : {})
			};
		}
	});
	// 路径处理
	joinParentPath(list);
	return cloneDeep(list);
}

/**
 * config menu with given params
 */
const menuParamRegex = /(?::)([\s\S]+?)((?=\/)|$)/g;

export function configureDynamicParamsMenu(menu: Menu, params: RouteParams) {
	const { path, paramPath } = menu;
	let realPath = paramPath || path;
	const matchArr = realPath.match(menuParamRegex);

	matchArr?.forEach(it => {
		const realIt = it.slice(1);
		if (params[realIt]) realPath = realPath.replace(`:${realIt}`, params[realIt] as string);
	});
	// save original param path.
	if (!paramPath && matchArr && matchArr.length > 0) menu.paramPath = path;

	menu.path = realPath;
	// children
	menu.children?.forEach(item => configureDynamicParamsMenu(item, params));
}
